package com.raymond.queue.client.netty;

import com.raymond.queue.client.QueueClient;
import com.raymond.queue.client.thread.PackRequestThread;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.EventLoop;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

/**
 * 连接处理
 *
 * @author :  raymond
 * @version :  V1.0
 * @date :  2021-07-14 11:39
 */
@ChannelHandler.Sharable
public class ReconnectHandler extends ChannelInboundHandlerAdapter {

    private final static Logger logger = LoggerFactory.getLogger(ReconnectHandler.class);
    /** 当前重试次数 **/
    private int retries = 0;
    /** 重连策略 **/
    private RetryPolicy retryPolicy;

    private QueueClient queueClient;

    public ReconnectHandler(QueueClient queueClient) {
        this.queueClient = queueClient;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        logger.debug("Successfully established a connection to the server.");
        retries = 0;
        ctx.fireChannelActive();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        if (retries == 0) {
            logger.debug("Lost the TCP connection with the server.");
            ctx.close();
        }

        boolean allowRetry = getRetryPolicy().allowRetry(retries);
        if (allowRetry) {

            long sleepTimeMs = getRetryPolicy().getSleepTimeMs(retries);

            logger.debug("Try to reconnect to the server after {}ms. Retry count: {}.", sleepTimeMs, ++retries);

            final EventLoop eventLoop = ctx.channel().eventLoop();
            eventLoop.schedule(() -> {
                logger.debug("Reconnecting ...");
                queueClient.connect();
            }, sleepTimeMs, TimeUnit.MILLISECONDS);
        }
        ctx.fireChannelInactive();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("", cause);
        ctx.close();
    }

    /**
     * 获取重连策略
     * @return 重连策略
     */
    private RetryPolicy getRetryPolicy() {
        if (this.retryPolicy == null) {
            this.retryPolicy = queueClient.getRetryPolicy();
        }
        return this.retryPolicy;
    }
}
